package com.zshy.base.monitor.domain.sender.factory.impl;


import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.zshy.base.core.contract.enums.ResultCodeEnum;
import com.zshy.base.kit.http.HttpKit;
import com.zshy.base.monitor.domain.contract.command.*;
import com.zshy.base.monitor.domain.contract.dto.MsgDTO;
import com.zshy.base.monitor.domain.contract.enums.*;
import com.zshy.base.monitor.domain.contract.exception.MonitorException;
import com.zshy.base.monitor.domain.sender.factory.AbstractSender;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 企微机器人
 *
 * @author zhouhengzhe
 */
public class QiWeiRobotSender extends AbstractSender {

    private final String dingUrl;

    public static final String BASE_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=";

    public QiWeiRobotSender(String key) {
        if (StringUtils.isBlank(key)){
            throw new MonitorException(ResultCodeEnum.PARAM_NULL);
        }
        dingUrl = BASE_URL + key;
    }

    /**
     * 发送图片类型(企微)
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E5%9B%BE%E7%89%87%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 图片（base64编码前）最大不能超过2M，支持JPG,PNG格式
     * @return 是否发送成功
     */
    @Override
    public Boolean sendMessageByImage(SendMessageByImageCommand command) {
        MsgDTO msgDTO = MsgDTO.builder()
                .msgType(QiWeiMsgTypeEnum.IMAGE.getCode())
                .image(MsgDTO.ImageDTO
                        .builder()
                        .base64(command.getBase64())
                        .md5(command.getMd5())
                        .build())
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 图文类型 发送图文消息（企微)
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E5%9B%BE%E6%96%87%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 图文内容图文类型
     * @return
     */
    @Override
    public Boolean sendMessageByNews(SendMessageByNewsCommand command) {
        MsgDTO msgDTO = MsgDTO.builder()
                .msgType(QiWeiMsgTypeEnum.NEWS.getCode())
                .news(MsgDTO.NewsDTO
                        .builder()
                        .articles(command.getArticles()
                                .stream()
                                .map(article -> MsgDTO.NewsDTO.ArticleDTO
                                        .builder()
                                        .title(article.getTitle())
                                        .description(article.getDescription())
                                        .url(article.getUrl())
                                        .picUrl(article.getPicUrl())
                                        .build()
                                ).toList())
                        .build())
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 文件类型 发送文件消息（企微)
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 图文内容图文类型
     * @return
     */
    @Override
    public Boolean sendMessageByFile(SendMessageByFileCommand command) {
        MsgDTO msgDTO = MsgDTO.builder()
                .msgType(QiWeiMsgTypeEnum.FILE.getCode())
                .file(MsgDTO.FileDTO
                        .builder()
                        .mediaId(command.getMediaId())
                        .build())
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 语音类型 发送语音消息（企微)
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E8%AF%AD%E9%9F%B3%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 语音内容
     * @return
     */
    @Override
    public Boolean sendMessageByVoice(SendMessageByVoiceCommand command) {
        MsgDTO msgDTO = MsgDTO.builder()
                .msgType(QiWeiMsgTypeEnum.VOICE.getCode())
                .voice(MsgDTO.VoiceDTO
                        .builder()
                        .mediaId(command.getMediaId())
                        .build())
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 模版卡片类型（企微）
     * - 文本通知模版卡片
     * - 图文展示模版卡片
     *
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E6%A8%A1%E7%89%88%E5%8D%A1%E7%89%87%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 模版卡片内容
     * @return
     */
    @Override
    public Boolean sendMessageByTemplateCard(SendMessageByTemplateCardCommand command) {
        if (Objects.nonNull(command.getMainTitle())
                && (StringUtils.isBlank(command.getMainTitle().getTitle()) && StringUtils.isBlank(command.getSubTitleText()))) {
            throw new MonitorException(ResultCodeEnum.TEMPLATE_CARD_MAIN_TITLE_NOT_EMPTY);

        }
        checkCardActionField(command);
        MsgDTO msgDTO = MsgDTO
                .builder()
                .msgType(QiWeiMsgTypeEnum.TEMPLATE_CARD.getCode())
                .templateCard(MsgDTO.TemplateCardDTO
                        .builder()
                        .source(MsgDTO.TemplateCardDTO.Source
                                .builder()
                                .desc(command.getSource().getDesc())
                                .iconUrl(command.getSource().getIconUrl())
                                .descColor(Objects.isNull(command.getSource().getDescColor()) ?
                                        DescColorEnum.DEFAULT.getCode() : command.getSource().getDescColor().getCode())
                                .build())
                        .mainTitle(MsgDTO.TemplateCardDTO.MainTitle
                                .builder()
                                .title(command.getMainTitle().getTitle())
                                .desc(command.getMainTitle().getDesc())
                                .build())
                        .emphasisContent(MsgDTO.TemplateCardDTO.EmphasisContent
                                .builder()
                                .title(command.getEmphasisContent().getTitle())
                                .desc(command.getEmphasisContent().getDesc())
                                .build())
                        .quoteArea(MsgDTO.TemplateCardDTO.QuoteArea
                                .builder()
                                .type(fillQuoteAreaTypeEnum(command).getCode())
                                .url(command.getQuoteArea().getUrl())
                                .appId(command.getQuoteArea().getAppId())
                                .pagePath(command.getQuoteArea().getPagePath())
                                .title(command.getQuoteArea().getTitle())
                                .quoteText(command.getQuoteArea().getQuoteText())
                                .build())
                        .subTitleText(command.getSubTitleText())
                        .horizontalContentList(getHorizontalContentLists(command.getHorizontalContentList()))
                        .jumpList(getJumpList(command.getJumpList()))
                        .cardAction(MsgDTO.TemplateCardDTO.CardAction
                                .builder()
                                .type(command.getCardAction().getType().getCode())
                                .url(command.getCardAction().getUrl())
                                .appId(command.getCardAction().getAppId())
                                .pagePath(command.getCardAction().getPagePath())
                                .build())
                        .build())
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 检查卡片动作字段填充卡片操作类型
     *
     * @param command
     */
    private static void checkCardActionField(SendMessageByTemplateCardCommand command) {
        if (CardActionTypeEnum.URL.equals(command.getCardAction().getType()) && StringUtils.isBlank(command.getCardAction().getUrl())) {
            throw new MonitorException(ResultCodeEnum.CARD_ACTION_URL_NOT_EMPTY);
        }
        if (CardActionTypeEnum.MINI_APP.equals(command.getCardAction().getType())
                && (StringUtils.isBlank(command.getCardAction().getAppId()) || StringUtils.isBlank(command.getCardAction().getPagePath()))) {
            throw new MonitorException(ResultCodeEnum.CARD_ACTION_APPID_OR_PAGEPATH_NOT_EMPTY);
        }
    }

    /**
     * 填充引用区域类型
     *
     * @param command
     * @return
     */
    private static QuoteAreaTypeEnum fillQuoteAreaTypeEnum(SendMessageByTemplateCardCommand command) {
        QuoteAreaTypeEnum quoteAreaTypeEnum = command.getQuoteArea().getType();
        if (Objects.isNull(quoteAreaTypeEnum)) {
            quoteAreaTypeEnum = QuoteAreaTypeEnum.NONE;
        }
        if (QuoteAreaTypeEnum.URL.equals(quoteAreaTypeEnum)) {
            if (StringUtils.isBlank(command.getQuoteArea().getUrl())) {
                throw new MonitorException(ResultCodeEnum.TEMPLATE_CARD_QUOTE_AREA_URL_NOT_EMPTY);
            }
        } else if (QuoteAreaTypeEnum.MINI_APP.equals(quoteAreaTypeEnum) && (StringUtils.isBlank(command.getQuoteArea().getAppId()) || StringUtils.isBlank(command.getQuoteArea().getPagePath()))) {
            throw new MonitorException(ResultCodeEnum.TEMPLATE_CARD_QUOTE_AREA_APP_ID_OR_PAGE_PATH_NOT_EMPTY);
        }
        return quoteAreaTypeEnum;
    }

    /**
     * 组装跳转列表
     *
     * @param jumpList 跳转列表跳转
     * @return
     */
    private static List<MsgDTO.TemplateCardDTO.JumpList> getJumpList(
            List<SendMessageByTemplateCardCommand.JumpList> jumpList) {
        if (CollectionUtils.isNotEmpty(jumpList)) {
            return Collections.emptyList();
        }
        return jumpList.stream().map(jump -> {
            JumpListTypeEnum type = jump.getType();
            if (Objects.isNull(type)) {
                type = JumpListTypeEnum.NONE;
            }
            if (JumpListTypeEnum.URL.equals(type) && StringUtils.isBlank(jump.getUrl())) {
                throw new MonitorException(ResultCodeEnum.TEMPLATE_CARD_JUMP_LIST_URL_NOT_EMPTY);
            }
            if (JumpListTypeEnum.MINI_APP.equals(type)
                    && (StringUtils.isBlank(jump.getAppId()) || StringUtils.isBlank(jump.getPagePath()))) {
                throw new MonitorException(ResultCodeEnum.JUMP_LIST_APP_ID_OR_PAGE_PATH_NOT_EMPTY);
            }
            return MsgDTO.TemplateCardDTO.JumpList
                    .builder()
                    .type(type.getCode())
                    .title(jump.getTitle())
                    .url(jump.getUrl())
                    .appId(jump.getAppId())
                    .pagePath(jump.getPagePath())
                    .build();
        }).toList();
    }

    /**
     * 组装水平内容列表
     *
     * @param horizontalContentList 模版卡片内容内容列表
     * @return 水平内容列表水平内容列表
     */
    private static List<MsgDTO.TemplateCardDTO.HorizontalContentList> getHorizontalContentLists(
            List<SendMessageByTemplateCardCommand.HorizontalContentList> horizontalContentList) {
        if (CollectionUtils.isEmpty(horizontalContentList)) {
            return Collections.emptyList();
        }
        return horizontalContentList
                .stream()
                .map(horizontalContent -> {
                    if (Objects.isNull(horizontalContent.getType())) {
                        throw new MonitorException(ResultCodeEnum.HORIZONTAL_CONTENT_LIST_TYPE_NULL);
                    }
                    if (HorizontalContentListTypeEnum.URL.equals(horizontalContent.getType())
                            && (StringUtils.isBlank(horizontalContent.getUrl()))) {
                        throw new MonitorException(ResultCodeEnum.HORIZONTAL_CONTENT_LIST_URL_NULL);

                    }
                    if (HorizontalContentListTypeEnum.FILE.equals(horizontalContent.getType())
                            && (StringUtils.isBlank(horizontalContent.getValue())
                            || StringUtils.isBlank(horizontalContent.getMediaId()))) {
                        throw new MonitorException(ResultCodeEnum.HORIZONTAL_CONTENT_LIST_FILE_VALUE_OR_MEDIA_ID_NULL);

                    }
                    if (HorizontalContentListTypeEnum.MEMBER_DETAIL.equals(horizontalContent.getType())
                            && (StringUtils.isBlank(horizontalContent.getUserId()))) {
                        throw new MonitorException(ResultCodeEnum.HORIZONTAL_CONTENT_LIST_USER_ID_NULL);
                    }
                    return MsgDTO.TemplateCardDTO.HorizontalContentList
                            .builder()
                            .type(horizontalContent.getType().getCode())
                            .keyName(horizontalContent.getKeyName())
                            .value(horizontalContent.getValue())
                            .url(horizontalContent.getUrl())
                            .mediaId(horizontalContent.getMediaId())
                            .userId(horizontalContent.getUserId())
                            .build();
                }).toList();
    }

    /**
     * 发送类型
     *
     * @return
     */
    @Override
    public String getType() {
        return MonitorEnum.QI_WEI.getCode();
    }

    /**
     * 发送文本消息（钉钉，企微都有）
     * <a href="https://open.dingtalk.com/document/orgapp/message-types-supported-by-enterprise-internal-robots#title-3tg-1on-mru">...</a>
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#%E6%96%87%E6%9C%AC%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 消息内容
     * @return 是否发送成功
     */
    @Override
    public Boolean sendMessageByText(SendMessageByTextCommand command) {
        MsgDTO.TextDTO textDTO = MsgDTO.TextDTO.builder()
                .content(command.getContent())
                .build();
        //如果是@所有人就不需要关注atUserIds和mobileList
        if (Boolean.TRUE.equals(command.getIsAtAll())) {
            textDTO.setMentionedList(List.of("@all"));
            textDTO.setMentionedMobileList(List.of("@all"));
        } else {
            if (CollectionUtils.isNotEmpty(command.getMobileList())) {
                textDTO.setMentionedMobileList(command.getMobileList());
            }
            if (CollectionUtils.isNotEmpty(command.getAtUserIds())) {
                textDTO.setMentionedList(command.getAtUserIds());
            }
        }
        MsgDTO msgDTO = MsgDTO.builder()
                .msgType(QiWeiMsgTypeEnum.TEXT.getCode())
                .text(textDTO)
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.parseObject(JSON.toJSONString(msgDTO))) != null;
    }

    /**
     * 发送Markdown 编辑格式的消息（钉钉，企微都有）
     * <a href="https://open.dingtalk.com/document/orgapp/message-types-supported-by-enterprise-internal-robots#title-n6d-5gn-lnw">...</a>
     * <a href="https://developer.work.weixin.qq.com/document/path/99110#markdown%E7%B1%BB%E5%9E%8B">...</a>
     *
     * @param command 消息内容
     * @return 是否发送成功
     */
    @Override
    public Boolean sendMessageByMarkdown(SendMessageByMarkdownCommand command) {
        MsgDTO.MarkDownDTO markDownDTO = MsgDTO.MarkDownDTO.builder()
                .content(command.getMarkdownText())
                .build();
        MsgDTO msgDTO = MsgDTO
                .builder()
                .msgType(QiWeiMsgTypeEnum.MARKDOWN.getCode())
                .markdown(markDownDTO)
                .build();
        return HttpKit.doPost(dingUrl, JSONObject.from(msgDTO)) != null;
    }
}
